package com.bii.gelapp;

import java.text.DecimalFormat;
import java.util.ArrayList;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;

public class CalculateTouchImageView extends ImageView {
	Matrix matrix;

	// We can be in one of these 3 states
	static final int NONE = 0;
	static final int DRAG = 1;
	static final int ZOOM = 2;
	int mode = NONE;

	// modes
	public static boolean editmode = false;

	// Remember some things for zooming
	PointF last = new PointF();
	PointF start = new PointF();
	float minScale = 1f;
	float maxScale = 4f;
	float[] m;

	// circledrawing
	float instx;
	float insty;

	int viewWidth, viewHeight;
	static final int CLICK = 3;
	float saveScale = 1f;
	protected float origWidth, origHeight;
	int oldMeasuredWidth, oldMeasuredHeight;

	ScaleGestureDetector mScaleDetector;
	MarkerStandard mss;

	Context context;

	Bitmap bmap;
	 //export this bitmap
	public static Bitmap valuesbmp;
	Mat drawmat;
	ArrayList<ConnectedComponent> componentlist = new ArrayList<ConnectedComponent>();
	ArrayList<ConnectedComponent> markerlist = new ArrayList<ConnectedComponent>();
	ArrayList componentvalues = new ArrayList();
	ArrayList markervalues = new ArrayList();
	public Bitmap originalBmp;

	public CalculateTouchImageView(Context context, Bitmap bmp) {
		super(context);
		originalBmp = bmp;
		sharedConstructing(context);

	}

	private void sharedConstructing(Context context) {
		// preparation for all the image loading and stuffs
		super.setClickable(true);
		this.context = context;
		mss = StartActivity.ms;

		bmap = originalBmp;
		drawmat = new Mat(bmap.getHeight(), bmap.getWidth(), CvType.CV_8U);

		componentlist = CalculateFullscreenActivity.componentlist;
		markerlist = CalculateFullscreenActivity.markerlist;
		markervalues = CalculateActivity2.markervalues;
		if (CalculateFullscreenActivity.componentvalues.size() != 0) {
			componentvalues = CalculateFullscreenActivity.componentvalues;
		}

		mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
		matrix = new Matrix();
		m = new float[9];
		setImageMatrix(matrix);
		// allow scaling of image by matrix
		setScaleType(ScaleType.MATRIX);

		setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				mScaleDetector.onTouchEvent(event);
				PointF curr = new PointF(event.getX(), event.getY());

				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					last.set(curr);
					start.set(last);
					mode = DRAG;
					
					if (editmode == true){
						Matrix inverse = new Matrix();
						getImageMatrix().invert(inverse);
						float[] touchPoint = new float[] { event.getX(),
								event.getY() };
						inverse.mapPoints(touchPoint);
						instx = touchPoint[0];
						insty = touchPoint[1];

					}
							
					break;

				case MotionEvent.ACTION_MOVE:
					if (mode == DRAG) {
						// get the new horizontal and vertical positions
						float deltaX = curr.x - last.x;
						float deltaY = curr.y - last.y;
						// if view width is larger than content size (original
						// width and height) returns 0
						float fixTransX = getFixDragTrans(deltaX, viewWidth,
								origWidth * saveScale);
						float fixTransY = getFixDragTrans(deltaY, viewHeight,
								origHeight * saveScale);
						matrix.postTranslate(fixTransX, fixTransY);
						fixTrans();
						last.set(curr.x, curr.y);
					}
					break;

				case MotionEvent.ACTION_UP:
					mode = NONE;
					int xDiff = (int) Math.abs(curr.x - start.x);
					int yDiff = (int) Math.abs(curr.y - start.y);
					if (xDiff < CLICK && yDiff < CLICK)
						performClick();
					
					if (editmode == true) {
						Point center = new Point(instx, insty);
						Log.d("tag1", "instx: " + instx + " insty: " + insty);
						Core.circle(drawmat, center, 10,  new Scalar(255, 0, 255));
						
						double distancetopmarker = insty - CalculateActivity2.topmarkercenter;	
						
						double wcd = distancetopmarker + CalculateActivity2.edw;
						double value = ScatterGraph.instantCalculate(wcd);
						
						Log.d("tag1", "distancetopmarker: " + distancetopmarker);
						Log.d("tag1", "edw: " + CalculateActivity2.edw);
						Log.d("tag1", "value: " + value);
						
						Point org = new Point(instx, insty);
						//float value = (Float) componentvalues.get(i);

						// String valuedisplay = " "+ value;
						String valuedisplay = String.format("%.1f", value);
						
						//DecimalFormat numberFormat = new DecimalFormat("#.00");
						//numberFormat.format(value);
						Core.putText(drawmat, "" + valuedisplay, org , 3, 0.75, new Scalar(255, 0 ,255), 1);
						
						Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
								Bitmap.Config.RGB_565);
						Utils.matToBitmap(drawmat, drawnbmp);
						setImageBitmap(drawnbmp);
					}
					break;

				case MotionEvent.ACTION_POINTER_UP:
					mode = NONE;
					break;
				}
				setImageMatrix(matrix);
				invalidate();
				return true; // indicate event was handled

			}

		});
		drawRectangles();

		if (componentvalues.size() == 0) {
			for (int i = 0; i < componentlist.size(); i++) {
				getValuesOfComponent(componentlist.get(i));
			}
		}

		// component values
		for (int i = 0; i < componentlist.size(); i++) {
			int top = componentlist.get(i).top;
			int bottom = componentlist.get(i).bottom;
			int left = componentlist.get(i).left;
			int right = componentlist.get(i).right;

			// int centerheight = (bottom + top)/2;
			int centerheight = bottom;
			// int centerwidth = (right + left)/2;
			int centerwidth = left;
			Point org = new Point(centerwidth, centerheight);

			float value = (Float) componentvalues.get(i);

			// String valuedisplay = " "+ value;
			String valuedisplay = String.format("%.1f", value);
			Core.putText(drawmat, valuedisplay, org, 3, 0.75, new Scalar(0, 0,
					255), 1);

			Log.d("tag1", "component " + i + "value: " + value + " center: "
					+ (top + bottom) / 2);

		}
		// marker values
		for (int i = 0; i < markerlist.size(); i++) {
			
			int top = markerlist.get(i).top;
			int bottom = markerlist.get(i).bottom;
			int left = markerlist.get(i).left;
			int right = markerlist.get(i).right;

			// int centerheight = (bottom + top)/2;
			int centerheight = bottom;
			// int centerwidth = (right + left)/2;
			int centerwidth = left;
			Point org = new Point(centerwidth, centerheight);

			//float value = (Float) markervalues.get(i);
			Integer value = (Integer)markervalues.get(i);
			String value1 = String.valueOf(value);
			
			// String valuedisplay = " "+ value;
			//String valuedisplay = String.format("%.1f", value1);
			Core.putText(drawmat, value1, org, 3, 0.75, new Scalar(0, 255,
					0), 1);
			
			/*
			int top = markerlist.get(i).top;
			int bottom = markerlist.get(i).bottom;
			int left = markerlist.get(i).left;
			int right = markerlist.get(i).right;

			// int centerheight = (bottom + top) / 2;
			// int centerwidth = (right + left) / 2;
			int centerheight = bottom;
			int centerwidth = left;
			Point org = new Point(centerwidth, centerheight);

			MarkerConnectedComponent mcc = mss.getmarkers().get(i);
			//int value = mcc.value;
			int value = (Integer) markervalues.get(i);
			
			String valuedisplay = " " + value;
			int[] msscolors = mss.getmarkers().get(i).color;
			int red = msscolors[0];
			int green = msscolors[1];
			int blue = msscolors[2];

			Core.putText(drawmat, valuedisplay, org, 3, 0.75, new Scalar(red,
					green, blue), 1);
			Log.d("tag1", "marker " + i + "value: " + valuedisplay
					+ " center: " + (top + bottom) / 2);
					*/
		}

		Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
				Bitmap.Config.RGB_565);
		Utils.matToBitmap(drawmat, drawnbmp);

		// Bitmap resizedbmp = Bitmap.createScaledBitmap(drawnbmp, 300, 300,
		// true);
		setImageBitmap(drawnbmp);
		valuesbmp = drawnbmp.copy(Config.ARGB_8888, true);
		/*
		 * Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
		 * Bitmap.Config.RGB_565); Utils.matToBitmap(drawmat, drawnbmp);
		 * setImageBitmap(drawnbmp);
		 */

	}

	public void setMaxZoom(float x) {
		maxScale = x;
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		@Override
		public boolean onScaleBegin(ScaleGestureDetector detector) {
			mode = ZOOM;
			return true;
		}

		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			float mScaleFactor = detector.getScaleFactor();
			// original scale is 1 times, zooming means to multiply it by the
			// scalefactor
			float origScale = saveScale;
			saveScale *= mScaleFactor;

			if (saveScale > maxScale) {
				// prevent zooming in too much
				saveScale = maxScale;
				mScaleFactor = maxScale / origScale;
			} else if (saveScale < minScale) {
				// prevent zooming out too much
				saveScale = minScale;
				mScaleFactor = minScale / origScale;
			}

			if (origWidth * saveScale <= viewWidth
					|| origHeight * saveScale <= viewHeight)
				matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
						viewHeight / 2);
			else
				matrix.postScale(mScaleFactor, mScaleFactor,
						detector.getFocusX(), detector.getFocusY());

			fixTrans();
			return true;
		}
	}

	void fixTrans() {
		matrix.getValues(m);
		float transX = m[Matrix.MTRANS_X];
		float transY = m[Matrix.MTRANS_Y];

		float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
		float fixTransY = getFixTrans(transY, viewHeight, origHeight
				* saveScale);

		if (fixTransX != 0 || fixTransY != 0)
			matrix.postTranslate(fixTransX, fixTransY);
	}

	float getFixTrans(float trans, float viewSize, float contentSize) {
		float minTrans, maxTrans;

		if (contentSize <= viewSize) {
			minTrans = 0;
			maxTrans = viewSize - contentSize;
		} else {
			minTrans = viewSize - contentSize;
			maxTrans = 0;
		}

		if (trans < minTrans)
			return -trans + minTrans;
		if (trans > maxTrans)
			return -trans + maxTrans;
		return 0;
	}

	float getFixDragTrans(float delta, float viewSize, float contentSize) {
		if (contentSize <= viewSize) {
			return 0;
		}
		return delta;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		viewWidth = MeasureSpec.getSize(widthMeasureSpec);
		viewHeight = MeasureSpec.getSize(heightMeasureSpec);

		//
		// Rescales image on rotation
		//
		if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
				|| viewWidth == 0 || viewHeight == 0)
			return;
		oldMeasuredHeight = viewHeight;
		oldMeasuredWidth = viewWidth;

		if (saveScale == 1) {
			// Fit to screen.
			float scale;

			Drawable drawable = getDrawable();
			if (drawable == null || drawable.getIntrinsicWidth() == 0
					|| drawable.getIntrinsicHeight() == 0)
				return;
			int bmWidth = drawable.getIntrinsicWidth();
			int bmHeight = drawable.getIntrinsicHeight();

			Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

			float scaleX = (float) viewWidth / (float) bmWidth;
			float scaleY = (float) viewHeight / (float) bmHeight;
			scale = Math.min(scaleX, scaleY);
			matrix.setScale(scale, scale);

			// Center the image
			float redundantYSpace = (float) viewHeight
					- (scale * (float) bmHeight);
			float redundantXSpace = (float) viewWidth
					- (scale * (float) bmWidth);
			redundantYSpace /= (float) 2;
			redundantXSpace /= (float) 2;

			matrix.postTranslate(redundantXSpace, redundantYSpace);

			origWidth = viewWidth - 2 * redundantXSpace;
			origHeight = viewHeight - 2 * redundantYSpace;
			setImageMatrix(matrix);
		}
		fixTrans();
	}

	private void drawRectangles() {
		Utils.bitmapToMat(bmap, drawmat);
		for (int i = 0; i < componentlist.size(); i++) {
			Core.rectangle(drawmat, new Point(componentlist.get(i).left,
					componentlist.get(i).top), new Point(
					componentlist.get(i).right, componentlist.get(i).bottom),
					new Scalar(255, 0, 0), 2);
		}
		for (int i = 0; i < markerlist.size(); i++) {
			Core.rectangle(drawmat, new Point(markerlist.get(i).left,
					markerlist.get(i).top), new Point(markerlist.get(i).right,
					markerlist.get(i).bottom), new Scalar(255, 255, 0), 2);
		}
		Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
				Bitmap.Config.RGB_565);
		Utils.matToBitmap(drawmat, drawnbmp);
		setImageBitmap(drawnbmp);

	};

	private void getValuesOfComponent(ConnectedComponent cc) {
		ConnectedComponent cctop;
		ConnectedComponent ccbottom;
		int topindex = 0;
		int bottomindex = 1;
		float comparedifferencetop = 9999;
		float comparedifferencebottom = 9999;

		int cccenterheight = (cc.top + cc.bottom) / 2;

		for (int j = 0; j < markerlist.size(); j++) {
			if (j + 1 != markerlist.size()) {
				float comparetopcenter = (markerlist.get(j).top + markerlist
						.get(j).bottom) / 2;
				float comparebottomcenter = (markerlist.get(j + 1).top + markerlist
						.get(j + 1).bottom) / 2;
				if (comparedifferencetop == 9999
						&& comparedifferencebottom == 9999) {

					comparedifferencetop = Math.abs(cccenterheight
							- comparetopcenter);
					comparedifferencebottom = Math.abs(cccenterheight
							- comparebottomcenter);

					// comparedifferencetop = cccenterheight - comparetopcenter;
					// comparedifferencebottom = cccenterheight -
					// comparebottomcenter;
					cctop = markerlist.get(j);
					ccbottom = markerlist.get(j + 1);
					topindex = j;
					bottomindex = j + 1;
				} else {
					if (cccenterheight > comparetopcenter
							&& cccenterheight < comparebottomcenter) {
						float differencetop = Math.abs(cccenterheight
								- comparetopcenter);
						float differencebottom = Math.abs(cccenterheight
								- comparebottomcenter);

						// float differencetop = cccenterheight -
						// comparetopcenter;
						// float differencebottom = cccenterheight -
						// comparebottomcenter;

						if (differencetop < comparedifferencetop
								&& differencebottom < comparedifferencebottom) {
							comparedifferencetop = differencetop;
							comparedifferencebottom = differencebottom;
							cctop = markerlist.get(j);
							ccbottom = markerlist.get(j + 1);
							topindex = j;
							bottomindex = j + 1;
						} else {
							;
						}
					} else {
						;
					}
				}

			}
		}

		// MarkerConnectedComponent mcc = mss.getmarkers().get(i+lowestindex);
		//MarkerConnectedComponent mcctop = mss.getmarkers().get(topindex);
		//MarkerConnectedComponent mccbottom = mss.getmarkers().get(bottomindex);
		ConnectedComponent mcctop = markerlist.get(topindex);
		ConnectedComponent mccbottom = markerlist.get(bottomindex);
		//float topvalue = mcctop.value;
		//float bottomvalue = mccbottom.value;
		float topvalue = (Float) markervalues.get(topindex);
		float bottomvalue = (Float) markervalues.get(bottomindex);

		float power = 0;

		float powerleft = (float) Math.log10(bottomvalue);
		float powerrightone = (float) (Math.log10(topvalue) - Math
				.log10(bottomvalue));
		float powerrighttwo = comparedifferencebottom;
		// float powerrightthree = comparedifferencetop;
		float comparetopcenter = (markerlist.get(topindex).top + markerlist
				.get(topindex).bottom) / 2;
		float comparebottomcenter = (markerlist.get(bottomindex).top + markerlist
				.get(bottomindex).bottom) / 2;

		float powerrightthree = Math
				.abs(comparetopcenter - comparebottomcenter);
		// float powerright = powerrightone * (powerrighttwo / powerrightthree);
		float powerright = powerrightone * (powerrighttwo / powerrightthree);

		power = powerleft + powerright;

		float ccvalue = (float) Math.pow(10, power);
		Log.d("tag1", "ccvalue: " + ccvalue);
		componentvalues.add(ccvalue);
	}
	
	public static Bitmap exportFinalImage(){
		return valuesbmp;
	}

}
